﻿#include "tm_pointlineitem.h"

#include <QPainter>
#include <QPen>
#include <QRectF>
#include <QDebug>
#include "qmath.h"

#include "bezier/bezier.h"


TM_PointLineItem::TM_PointLineItem(QPointF start,QPointF end,QString startItemId,QString endItemId,int lineType,QGraphicsItem *parent):
    QGraphicsItem(parent)
{
    m_start = start;m_end = end;m_startItemId = startItemId;m_endItemId = endItemId;
    m_LineDirection = lineType;

    // m_K = double(double(m_end.y()-m_start.y())/double(m_end.x()-m_start.x()));
    // m_B = double(m_start.y()-double(m_K*m_start.x()));

    // m_start_bezier.setX(((m_end.x() - m_start.x())/3)+ m_start.x());
    // m_start_bezier.setY((m_start_bezier.x()*m_K)+m_B);

    // m_end_bezier.setX(((m_end.x() - m_start.x())/2) + m_start.x());
    // m_end_bezier.setY((m_end_bezier.x()*m_K)+m_B);

    m_start_bezier = (m_start+m_end)/2;
    m_end_bezier = (m_start+m_end)/2;

    PolygonItem=new QGraphicsPolygonItem(this);
    PolygonItem->setData(ItemDesciption,ItemBezier_Direct);
    PolygonItem->setData(ItemId,ItemBezier_Direct);
    PolygonItem->setPen(QPen(Qt::green,0));
    PolygonItem->setBrush(QBrush(Qt::green));

    m_len = fabs(sqrt(((m_end.x()-m_start.x()) * (m_end.x()-m_start.x()))+((m_end.y()-m_start.y()) * (m_end.y()-m_start.y()))));
    //setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable|QGraphicsItem::ItemIsFocusable);
    //qDebug()<<"TM_PointLineItem::TM_PointLineItem"<<m_K<<m_B<<m_start<<m_end<<m_start_bezier<<m_end_bezier;
    update_bezierData();
    setZValue(1);
}

TM_PointLineItem::~TM_PointLineItem()
{

}

void TM_PointLineItem::setLineDerice(int Direct)
{
    m_LineDirection = Direct;
    update_bezierData();
}

void TM_PointLineItem::update_bezierData()
{
    m_PointList.clear();
    // Create a cubic bezier with 4 points. Visualized at https://www.desmos.com/calculator/fivneeogmh
    bezier::Bezier<3> cubicBezier({ {m_start.x(), m_start.y()}, {m_start_bezier.x(), m_start_bezier.y()}, {m_end_bezier.x(), m_end_bezier.y()}, {m_end.x(), m_end.y()} });
    //bezier::Bezier<3> cubicBezier({ {120, 160}, {35, 200}, {220, 260}, {220, 40} });
    // Get coordinates on the curve from a value between 0 and 1 (values outside this range are also valid because of the way bezier curves are defined).
    bezier::Point p;
    p = cubicBezier.valueAt(0);   // (120, 160)
    p = cubicBezier.valueAt(0.5); // (138.125, 197.5)

    // Get coordinate values for a single axis. Currently only supports 2D.
    double value;
    value = cubicBezier.valueAt(1, 0);    // 220 (x-coordinate at t = 1)
    value = cubicBezier.valueAt(0.75, 1); // 157.1875 (y-coordinate at t = 0.75)
    value = cubicBezier.length();         // 272.85 (Arc length of the bezier curve)

    data1.setX(cubicBezier.valueAt(0.4, 0));
    data1.setY(cubicBezier.valueAt(0.4, 1));
    data2.setX(cubicBezier.valueAt(0.5, 0));
    data2.setY(cubicBezier.valueAt(0.5, 1));

    setLine_Parameter();

    QPointF start_Len = m_start;
    for(double i=0;i<1;i=i+0.005)
    {
        QPointF data;
        data.setX(cubicBezier.valueAt(i, 0));
        data.setY(cubicBezier.valueAt(i, 1));
        //qDebug()<<"sssssssssss"<<QString::number(i)<<","<<data.x()<<data.y();
        QPointF len = data - start_Len;

        if(((len.x()*len.x()) + (len.y()*len.y()) > (0.1/g_map_resolution)*(0.1/g_map_resolution))
                || i == 0 || i == 0.99)
        {
            start_Len = data;
            m_PointList.append(data);
        }
        // bezier::Point ppp;
        // ppp = cubicBezier.valueAt(i);   // (120, 160)
        // qDebug()<<"zzzzzzzzzzzzzzzzzzzzzzz"<<QString::number(ppp.x)<<QString::number(ppp.y);
    }

    //贝塞尔焦点有可能与开始点和结束点在同一条直线上 获取边框失败，以下代码不执行
    return;
    // Translate and rotate bezier curves.
    bezier::Bezier<3> copy = cubicBezier;
    copy.translate(10, 15);      // Translate 10 in x-direction, 15 in y-direction
    copy.rotate(0.5);            // Rotate 0.5 radians around the origin
    copy.rotate(3.14, {-5, 20}); // Rotate 3.14 radians around (-5, 20)

    // Get normals along the bezier curve.
    bezier::Normal normal = cubicBezier.normalAt(0.75); // Get normalized normal at t = 0.75. Add false as second argument to disable normalization.
    double angle = normal.angle();       // Angle in radians
    double angleDeg = normal.angleDeg(); // Angle in degrees

    // Get tangents along the bezier curve.
    bezier::Tangent tangent = cubicBezier.tangentAt(0.25); // Get normalized tangent at t = 0.25. Add false as second argument to disable normalization.
    angle = tangent.angle();       // Angle in radians
    angleDeg = tangent.angleDeg(); // Angle in degrees

    // Get derivatives of the bezier curve, resulting in a bezier curve of one order less.
    bezier::Bezier<2> db  = cubicBezier.derivative(); // First derivative
    bezier::Bezier<1> ddb = db.derivative();          // Second derivative

    // Get extreme values of the bezier curves.
    bezier::ExtremeValues xVals = cubicBezier.derivativeZero();  // Contains 3 extreme value locations: t = 0.186811984, t = 1.0 and t = 0.437850952
    bezier::ExtremeValue const& xVal = xVals[0];                 // Contains t value and axis for the first extreme value
    bezier::Point xValCoord = cubicBezier.valueAt(xVal.t);       // Get the coordinates for the first extreme value (97.6645355, 182.55565)
    bezier::ExtremePoints xPoints = cubicBezier.extremePoints(); // Or get all the extreme points directly (includes 0 and 1)

    // Get bounding boxes of the bezier curves.
    bezier::AABB aabb = cubicBezier.aabb();            // Axis Aligned Bounding Box
    aabb = cubicBezier.aabb(xPoints);                  // Or get from extreme points (if you already have them) to reduce calculation time

    bezier::TightBoundingBox tbb = cubicBezier.tbb();  // Tight bounding box

    double minX = std::numeric_limits<double>::max();
    double maxX = -std::numeric_limits<double>::max();
    double minY = std::numeric_limits<double>::max();
    double maxY = -std::numeric_limits<double>::max();

    for (size_t i = 0; i < xPoints.size(); i++)
    {
        if (xPoints[i].x > maxX)
            maxX = xPoints[i].x;
        if (xPoints[i].x < minX)
            minX = xPoints[i].x;
        if (xPoints[i].y > maxY)
            maxY = xPoints[i].y;
        if (xPoints[i].y < minY)
            minY = xPoints[i].y;
    }
    // Split the bezier curve at desired points. The left and right parts are new bezier curves
    // of the same order as the original curve.
    auto split = cubicBezier.split(0.5);
    auto &left  = split.left;  // Left part of the split
    auto &right = split.right; // Right part of the split

    // Find the mid point on the curve by arch length.
    double tAtMidPoint = cubicBezier.archMidPoint();           // 0.70718
    bezier::Point midPoint = cubicBezier.valueAt(tAtMidPoint); // (183.837, 168.768)


}

void TM_PointLineItem::setBezierPoint(QPointF  start, QPointF  end, QPointF  bezierstart, QPointF  bezierend)
{
    m_start = start;
    m_end = end;
    m_start_bezier = bezierstart;
    m_end_bezier = bezierend;
    update_bezierData();
}

void TM_PointLineItem::setStartPoint(QPointF  start,double ScaleValue)
{
    m_start = start;
    update_bezierData();

}
void TM_PointLineItem::setEndPoint(QPointF  end,double ScaleValue)
{
    m_end = end;
    update_bezierData();
}
void TM_PointLineItem::setStart_BezierPoint(QPointF  start,double ScaleValue)
{
    m_start_bezier = start;
    update_bezierData();
}
void TM_PointLineItem::setEnd_BezierPoint(QPointF  end,double ScaleValue)
{
    m_end_bezier = end;
    update_bezierData();
}

void TM_PointLineItem::setLine_Parameter(QString type,QString data)
{
    if(type.contains(":start->end"))
    {
        QString key = type.mid(0,type.indexOf(":start->end"));
        m_startToend.map[key] = data;
    }
    else if(type.contains(":end->start"))
    {
        QString key = type.mid(0,type.indexOf(":end->start"));
        m_endTostart.map[key] = data;
    }

    QPolygonF   points;
    if(m_LineDirection == 1)
    {
        if(m_startToend.map["Reverse"].toBool())
        {//支持倒向
            PolygonItem->setPen(QPen(Qt::blue,0));
            PolygonItem->setBrush(QBrush(Qt::blue));
        }
        else
        {//不支持倒向
            PolygonItem->setPen(QPen(Qt::red,0));
            PolygonItem->setBrush(QBrush(Qt::red));
        }

        points.append(QPointF(2,0)*2);
        points.append(QPointF(-1,-1)*2);
        points.append(QPointF(-1,1)*2);

        PolygonItem->setPolygon(points);
    }
    else if(m_LineDirection == 2)
    {
        if(m_endTostart.map["Reverse"].toBool())
        {//支持倒向
            PolygonItem->setPen(QPen(Qt::blue,0));
            PolygonItem->setBrush(QBrush(Qt::blue));
        }
        else
        {//不支持倒向
            PolygonItem->setPen(QPen(Qt::red,0));
            PolygonItem->setBrush(QBrush(Qt::red));
        }
        points.append(QPointF(-2,0)*2);
        points.append(QPointF(1,-1)*2);
        points.append(QPointF(1,1)*2);
        PolygonItem->setPolygon(points);
    }
    else if(m_LineDirection == 3)
    {
        points.append(QPointF(-2,0)*2);
        points.append(QPointF(0,-1)*2);
        points.append(QPointF(2,0)*2);
        points.append(QPointF(0,1)*2);
        // 创建线性渐变对象
        //QRadialGradient gradient(QPointF(-2,0)*2, 4*2);
        QLinearGradient gradient(QPointF(-2,0)*2,QPointF(2,0)*2);

        if(m_startToend.map["Reverse"].toBool())
        {//支持倒向
            gradient.setColorAt(0.51,Qt::blue);
            gradient.setColorAt(1,Qt::blue);
        }
        else
        {
            gradient.setColorAt(0.51,Qt::red);
            gradient.setColorAt(1,Qt::red);
        }

        if(m_endTostart.map["Reverse"].toBool())
        {//支持倒向
            gradient.setColorAt(0,Qt::blue);
            gradient.setColorAt(0.5,Qt::blue);
        }
        else
        {
            gradient.setColorAt(0,Qt::red);
            gradient.setColorAt(0.5,Qt::red);
        }
        PolygonItem->setPen(QPen(Qt::red,0));
        PolygonItem->setBrush(QBrush(gradient));
        PolygonItem->setPolygon(points);
    }

    double k = (data1.y() - data2.y())/ (data1.x() - data2.x());
    double jiaodu = double(atan(k)) * double(180) / double(3.1415962);
    if(data2.y()<data1.y() && data2.x()<data1.x())
        PolygonItem->setRotation(jiaodu-180);
    else if(data2.y()>data1.y() && data2.x()<data1.x())
        PolygonItem->setRotation(jiaodu+180);
    else
        PolygonItem->setRotation(jiaodu);

    PolygonItem->setPos(data1-m_start);
}


QRectF TM_PointLineItem::boundingRect() const
{
    return QRectF(0,0,m_end.x()-m_start.x(),m_end.y()-m_start.y());
}

void TM_PointLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)

    painter->setPen(QPen(QColor(224,80,70),1/g_curScaleValue < 1 ? 1 : 1/g_curScaleValue));
    if(g_StationPointList.contains(m_startItemId) && g_StationPointList.contains(m_endItemId))
    {
        int one = 0,two = 0;
        for(int i=0;i<g_StationPointList.length();i++)
        {
            if(m_startItemId == g_StationPointList[i])
                one = i;
            if(m_endItemId == g_StationPointList[i])
                two = i;
        }
        if(m_LineDirection == 1 && one - two == -1)
        {
            painter->setPen(QPen(Qt::blue,1));//导航路线途经点
        }
        else if(m_LineDirection == 2 && one - two == 1)
        {
            painter->setPen(QPen(Qt::blue,1));//导航路线途经点
        }
        else if(m_LineDirection == 3 && (one - two == 1 || one - two == -1) )
        {
            painter->setPen(QPen(Qt::blue,1));//导航路线途经点
        }
    }
    // painter->drawLine(-50,-50,-50,50);
    // painter->drawLine(-50,-50,50,50);
    // painter->drawLine(50,-50,50,50);
    // painter->drawLine(0,0,0,10);

    //qDebug()<<"m_PointList.length()="<<m_PointList.length()<<m_PointList;
    for(int i=0;i<m_PointList.length()-1;i++)
    {
        QPointF startPoint = (QPointF)m_PointList[i];
        QPointF EndPoint = (QPointF)m_PointList[i+1];
        painter->drawLine(startPoint - m_start,EndPoint - m_start);
    }

    //painter->drawLine(0,0,m_end.x()-m_start.x(),m_end.y()-m_start.y());

    //qDebug()<<"m_PointList="<<m_PointList;

    if(g_is_OpenMapEdit)
    {
        painter->setPen(QPen(Qt::red,0.5,Qt::DashLine));
        painter->drawLine(m_start - m_start,m_start_bezier - m_start);
        painter->drawLine(m_start_bezier - m_start,m_end_bezier - m_start);
        painter->drawLine(m_end_bezier - m_start,m_end - m_start);
    }
    return;


    m_len = fabs(sqrt(((m_end.x()-m_start.x()) * (m_end.x()-m_start.x()))+((m_end.y()-m_start.y()) * (m_end.y()-m_start.y()))));
    //qDebug()<<"(m_end.y()-m_start.y()="<<(m_end.y()-m_start.y())<<(m_end.x()-m_start.x());
    double k = double(m_end.y()-m_start.y())/double(m_end.x()-m_start.x());
    //qDebug()<<"k="<<QString::number(k);
    double jiaodu = double(atan(k)) * double(180) / double(3.1415962);
    //qDebug()<<"m_len="<<m_len<<",jiaodu="<<jiaodu;
    painter->drawLine(0,0,m_len,0);
    if(m_jiaodu != jiaodu)
    {
        if(m_end.y()<m_start.y() && m_end.x()<m_start.x())
            setRotation(jiaodu-180);
        else if(m_end.y()>m_start.y() && m_end.x()<m_start.x())
            setRotation(jiaodu+180);
        else
            setRotation(jiaodu);
    }
    m_jiaodu = jiaodu;
}
